package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.aliyun.iot20180120.Client;
import com.aliyun.iot20180120.models.*;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zzyl.base.PageResponse;
import com.zzyl.constant.CacheConstants;
import com.zzyl.dto.DeviceDto;
import com.zzyl.dto.DevicePageQueryDto;
import com.zzyl.entity.Device;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.DeviceMapper;
import com.zzyl.properties.AliIoTConfigProperties;
import com.zzyl.service.DeviceService;
import com.zzyl.vo.DeviceDataGraphVo;
import com.zzyl.vo.DeviceVo;
import com.zzyl.vo.ProductVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class DeviceServiceImpl implements DeviceService {

    @Autowired
    private Client client;

    @Autowired
    private AliIoTConfigProperties aliIoTConfigProperties;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private DeviceMapper deviceMapper;

    /**
     * 同步产品列表
     */
    @Override
    public void syncProductList() {
        QueryProductListRequest queryProductListRequest = new QueryProductListRequest();
        queryProductListRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        queryProductListRequest.setCurrentPage(1);
        queryProductListRequest.setPageSize(100);
        QueryProductListResponse queryProductListResponse;
        try {
            queryProductListResponse = client.queryProductList(queryProductListRequest);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_LIST_PRODUCT_ERROR);
        }
        if (queryProductListResponse.getBody().success) {
            List<QueryProductListResponseBody.QueryProductListResponseBodyDataListProductInfo> productInfo = queryProductListResponse.getBody().getData().getList().getProductInfo();
            //存入redis中
            redisTemplate.opsForValue().set(CacheConstants.IOT_DEVICE_PRODUCT, JSONUtil.toJsonStr(productInfo));
        }
    }

    /**
     * 查询所有产品列表
     *
     * @return
     */
    @Override
    public List<ProductVo> allProduct() {
        //从redis中获取所有产品列表
        List<ProductVo> productVoList = JSONUtil.toList(redisTemplate.opsForValue().get(CacheConstants.IOT_DEVICE_PRODUCT), ProductVo.class);
        return productVoList;
    }

    /**
     * 注册设备
     *
     * @param deviceDto
     */
    @Override
    public void registerDevice(DeviceDto deviceDto) {
        //查询数据库中是否纯在同名设备
        int count = deviceMapper.queryDeviceByDeviceName(deviceDto.getDeviceName());
        if (count > 0) {
            //存在抛出异常
            throw new BaseException(BasicEnum.DEVICE_NAME_EXIST);
        }

        //注册设备
        RegisterDeviceRequest registerDeviceRequest = new RegisterDeviceRequest();
        registerDeviceRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        registerDeviceRequest.setDeviceName(deviceDto.getDeviceName());
        registerDeviceRequest.setProductKey(deviceDto.getProductKey());
        registerDeviceRequest.setNickname(deviceDto.getNickname());
        RegisterDeviceResponse registerDeviceResponse;
        try {
            registerDeviceResponse = client.registerDevice(registerDeviceRequest);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }
        if (!registerDeviceResponse.getBody().success) {
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }

        //封装插入数据库设备信息
        Device device = BeanUtil.toBean(deviceDto, Device.class);
        if (deviceDto.getLocationType().equals(0)) {
            //绑定位置为随身设备,物理位置设为-1
            device.setPhysicalLocationType(-1);
        }

        //封装设备id
        device.setIotId(registerDeviceResponse.getBody().getData().getIotId());

        //封装产品名称，先查询产品
        QueryProductRequest queryProductRequest = new QueryProductRequest();
        queryProductRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        queryProductRequest.setProductKey(deviceDto.getProductKey());
        QueryProductResponse queryProductResponse;
        try {
            queryProductResponse = client.queryProduct(queryProductRequest);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_PRODUCT_ERROR);
        }

        if (!queryProductResponse.getBody().success) {
            throw new BaseException(BasicEnum.IOT_QUERY_PRODUCT_ERROR);
        }
        device.setProductName(queryProductResponse.getBody().getData().getProductName());

        //封装是否包含门禁
        device.setHaveEntranceGuard(0);

        //插入数据库
        try {
            deviceMapper.insertDevice(device);
        } catch (Exception e) {
            //插入失败，删除阿里云注册的设备
            DeleteDeviceRequest deleteDeviceRequest = new DeleteDeviceRequest();
            deleteDeviceRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
            deleteDeviceRequest.setProductKey(deviceDto.getProductKey());
            deleteDeviceRequest.setDeviceName(deviceDto.getDeviceName());
            deleteDeviceRequest.setIotId(registerDeviceResponse.getBody().getData().getIotId());
            DeleteDeviceResponse deleteDeviceResponse;
            try {
                deleteDeviceResponse = client.deleteDevice(deleteDeviceRequest);
            } catch (Exception ex) {
                throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
            }
            if (!deleteDeviceResponse.getBody().success) {
                throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
            }
            throw new BaseException(BasicEnum.MYSQL_INSERT_DEVICE_ERROR);
        }
    }

    /**
     * 分页查询设备列表
     *
     * @param devicePageQueryDto
     * @return
     */
    @Override
    public PageResponse<DeviceVo> pageQueryDevice(DevicePageQueryDto devicePageQueryDto) {
        PageHelper.startPage(devicePageQueryDto.getPageNum(), devicePageQueryDto.getPageSize());
        Page<DeviceVo> page = deviceMapper.queryPageQueryDevice(devicePageQueryDto);
        return PageResponse.of(page, DeviceVo.class);
    }

    /**
     * 查询设备详细数据
     *
     * @param deviceDto
     * @return
     */
    @Override
    public DeviceVo queryDeviceDetail(DeviceDto deviceDto) {
        Device device = BeanUtil.toBean(deviceDto, Device.class);
        //获取数据库的设备信息
        DeviceVo deviceVo = deviceMapper.queryDeviceDetailByIotId(device.getIotId());

        //获取iot平台的设备信息
        QueryDeviceDetailRequest queryDeviceDetailRequest = new QueryDeviceDetailRequest();
        queryDeviceDetailRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        queryDeviceDetailRequest.setProductKey(deviceDto.getProductKey());
        queryDeviceDetailRequest.setIotId(deviceDto.getIotId());
        QueryDeviceDetailResponse queryDeviceDetailResponse;
        try {
            queryDeviceDetailResponse = client.queryDeviceDetail(queryDeviceDetailRequest);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }

        if (!queryDeviceDetailResponse.getBody().success) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }

        //把iot平台的设备信息拷贝到deviceVo返回
        QueryDeviceDetailResponseBody.QueryDeviceDetailResponseBodyData data = queryDeviceDetailResponse.getBody().getData();
        BeanUtil.copyProperties(data, deviceVo);
        return deviceVo;
    }

    /**
     * 查询指定设备的物模型运行状态
     *
     * @param deviceDto
     */
    @Override
    public QueryDevicePropertyStatusResponseBody.QueryDevicePropertyStatusResponseBodyData queryDevicePropertyStatus(DeviceDto deviceDto) {
        QueryDevicePropertyStatusRequest queryDevicePropertyStatusRequest = new QueryDevicePropertyStatusRequest();
        queryDevicePropertyStatusRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        queryDevicePropertyStatusRequest.setProductKey(deviceDto.getProductKey());
        queryDevicePropertyStatusRequest.setDeviceName(deviceDto.getDeviceName());
        QueryDevicePropertyStatusResponse queryDevicePropertyStatusResponse;
        try {
            queryDevicePropertyStatusResponse = client.queryDevicePropertyStatus(queryDevicePropertyStatusRequest);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_PROPERTY_STATUS_ERROR);
        }

        if (!queryDevicePropertyStatusResponse.getBody().success) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_PROPERTY_STATUS_ERROR);
        }

        QueryDevicePropertyStatusResponseBody.QueryDevicePropertyStatusResponseBodyData data = queryDevicePropertyStatusResponse.getBody().getData();
        return data;
    }

    /**
     * 查看指定产品的已发布物模型中的功能定义详情
     *
     * @param deviceDto
     * @return
     */
    @Override
    public Map<String, Object> QueryThingModelPublished(DeviceDto deviceDto) {
        QueryThingModelPublishedRequest queryThingModelPublishedRequest = new QueryThingModelPublishedRequest();
        queryThingModelPublishedRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        queryThingModelPublishedRequest.setProductKey(deviceDto.getProductKey());
        QueryThingModelPublishedResponse queryThingModelPublishedResponse;
        try {
            queryThingModelPublishedResponse = client.queryThingModelPublished(queryThingModelPublishedRequest);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_PRODUCT_FUNCTION_ERROR);
        }

        if (!queryThingModelPublishedResponse.getBody().success) {
            throw new BaseException(BasicEnum.IOT_QUERY_PRODUCT_FUNCTION_ERROR);
        }

        HashMap<String, Object> map = new HashMap<>();
        map.put("thingModelJson", queryThingModelPublishedResponse.getBody().getData().getThingModelJson());
        return map;
    }

    /**
     * 修改设备备注名称
     *
     * @param deviceDto
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateDevice(DeviceDto deviceDto) {
        Device device = BeanUtil.toBean(deviceDto, Device.class);

        //修改数据库设备备注名称
        deviceMapper.updateDevice(device);

        //修改iot平台设备备注名称
        BatchUpdateDeviceNicknameRequest updateDeviceNicknameRequest = new BatchUpdateDeviceNicknameRequest();
        List<BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo> deviceNicknameInfos = new ArrayList<>();

        BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo batchUpdateDeviceNicknameRequestDeviceNicknameInfo =
                new BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo();
        batchUpdateDeviceNicknameRequestDeviceNicknameInfo.setNickname(deviceDto.getNickname());
        batchUpdateDeviceNicknameRequestDeviceNicknameInfo.setProductKey(deviceDto.getProductKey());
        batchUpdateDeviceNicknameRequestDeviceNicknameInfo.setDeviceName(deviceDto.getDeviceName());

        deviceNicknameInfos.add(batchUpdateDeviceNicknameRequestDeviceNicknameInfo);
        updateDeviceNicknameRequest.setDeviceNicknameInfo(deviceNicknameInfos);
        updateDeviceNicknameRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        BatchUpdateDeviceNicknameResponse batchUpdateDeviceNicknameResponse;
        try {
            batchUpdateDeviceNicknameResponse = client.batchUpdateDeviceNickname(updateDeviceNicknameRequest);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_BATCH_UPDATE_DEVICE_ERROR);
        }

        if (!batchUpdateDeviceNicknameResponse.getBody().success) {
            throw new BaseException(BasicEnum.IOT_BATCH_UPDATE_DEVICE_ERROR);
        }
    }

    /**
     * 删除设备
     *
     * @param deviceDto
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteDevice(DeviceDto deviceDto) {
        Device device = BeanUtil.toBean(deviceDto, Device.class);

        //删除数据库设备
        deviceMapper.deleteDeviceByIotId(device.getIotId());

        //删除iot平台设备
        DeleteDeviceRequest deleteDeviceRequest = new DeleteDeviceRequest();
        deleteDeviceRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        deleteDeviceRequest.setProductKey(deviceDto.getProductKey());
        deleteDeviceRequest.setIotId(device.getIotId());
        DeleteDeviceResponse deleteDeviceResponse;
        try {
            deleteDeviceResponse = client.deleteDevice(deleteDeviceRequest);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
        }

        if (!deleteDeviceResponse.getBody().success) {
            throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
        }
    }

    /**
     * 按天统计查询指标数据
     *
     * @param iotId
     * @param endTime
     * @param functionId
     * @param startTime
     * @return
     */
    @Override
    public List<DeviceDataGraphVo> queryDeviceDataListByDay(String iotId, Long endTime, String functionId, Long startTime) {
        LocalDateTime startDateTime = LocalDateTimeUtil.of(startTime);
        LocalDateTime endDateTime = LocalDateTimeUtil.of(endTime);
        List<DeviceDataGraphVo> deviceDataGraphVos = deviceMapper.queryDeviceDataListByDay(iotId, startDateTime, functionId, endDateTime);
        Map<String, Double> deviceDataGraphVoMap = deviceDataGraphVos.stream().collect(Collectors.toMap(DeviceDataGraphVo::getDateTime, DeviceDataGraphVo::getDataValue));
        //获取一天的空集合数据
        List<DeviceDataGraphVo> deviceDataGraphVoList = DeviceDataGraphVo.dayInstance(startDateTime);
        //组装数据
        deviceDataGraphVoList.forEach(deviceDataGraphVo -> {
            if (ObjectUtil.isNotEmpty(deviceDataGraphVoMap.get(deviceDataGraphVo.getDateTime()))) {
                deviceDataGraphVo.setDataValue(deviceDataGraphVoMap.get(deviceDataGraphVo.getDateTime()));
            }
        });
        return deviceDataGraphVoList;
    }

    /**
     * 按周统计查询指标数据
     *
     * @param iotId
     * @param endTime
     * @param functionId
     * @param startTime
     * @return
     */
    @Override
    public List<DeviceDataGraphVo> queryDeviceDataListByWeek(String iotId, Long endTime, String functionId, Long startTime) {
        LocalDateTime startDateTime = LocalDateTimeUtil.of(startTime);
        LocalDateTime endDateTime = LocalDateTimeUtil.of(endTime);
        List<DeviceDataGraphVo> deviceDataGraphVos = deviceMapper.queryDeviceDataListByWeek(iotId, startDateTime, functionId, endDateTime);
        Map<String, Double> deviceDataGraphVoMap = deviceDataGraphVos.stream().collect(Collectors.toMap(DeviceDataGraphVo::getDateTime, DeviceDataGraphVo::getDataValue));
        //获取一天的空集合数据
        List<DeviceDataGraphVo> deviceDataGraphVoList = DeviceDataGraphVo.weekInstance(startDateTime);
        //组装数据
        deviceDataGraphVoList.forEach(deviceDataGraphVo -> {
            if (ObjectUtil.isNotEmpty(deviceDataGraphVoMap.get(deviceDataGraphVo.getDateTime()))) {
                deviceDataGraphVo.setDataValue(deviceDataGraphVoMap.get(deviceDataGraphVo.getDateTime()));
            }
        });
        return deviceDataGraphVoList;
    }
}
